package com.example.movie.utils

import java.lang.reflect.Method

/**
 * @author  zr
 */
object BeanUtils {
    /**
     * 利用反射实现对象之间属性复制
     * @param from
     * @param to
     */
    @Throws(Exception::class)
    fun copyProperties(from: Any, to: Any) {
        copyPropertiesExclude(from, to, null)
    }

    /**
     * 复制对象属性
     * @param from
     * @param to
     * @param excludeArray 排除属性列表
     * @throws Exception
     */
    @Throws(Exception::class)
    fun copyPropertiesExclude(from: Any, to: Any, excludeArray: Array<String?>?) {
        var excludesList: List<String>? = null
        if (excludeArray != null && excludeArray.isNotEmpty()) {
            excludesList = listOf(*excludeArray) as List<String>? //构造列表对象
        }
        val fromMethods = from.javaClass.declaredMethods
        val toMethods = to.javaClass.declaredMethods
        var fromMethod: Method? = null
        var toMethod: Method? = null
        var fromMethodName: String? = null
        var toMethodName: String? = null
        for (i in fromMethods.indices) {
            fromMethod = fromMethods[i]
            fromMethodName = fromMethod.name
            if (!fromMethodName.contains("get") || fromMethodName.contains("getId")) continue
            //排除列表检测
            if (excludesList != null && excludesList.contains(
                    fromMethodName.substring(3).toLowerCase()
                )
            ) {
                continue
            }
            toMethodName = "set" + fromMethodName.substring(3)
            toMethod = findMethodByName(toMethods, toMethodName)
            if (toMethod == null) continue
            val value = fromMethod.invoke(from, *arrayOfNulls(0)) ?: continue
            //集合类判空处理
            if (value is Collection<*>) {
                if (value.size <= 0) continue
            }
            toMethod.invoke(to, *arrayOf(value))
        }
    }

    /**
     * 对象属性值复制，仅复制指定名称的属性值
     * @param from
     * @param to
     * @param includeArray
     * @throws Exception
     */
    @Throws(Exception::class)
    fun copyPropertiesInclude(from: Any, to: Any, includeArray: Array<String?>?) {
        var includesList: List<String>? = if (includeArray != null && includeArray.isNotEmpty()) {
            listOf(*includeArray) as List<String>? //构造列表对象
        } else {
            return
        }
        val fromMethods = from.javaClass.declaredMethods
        val toMethods = to.javaClass.declaredMethods
        var fromMethod: Method? = null
        var toMethod: Method? = null
        var fromMethodName: String? = null
        var toMethodName: String? = null
        for (i in fromMethods.indices) {
            fromMethod = fromMethods[i]
            fromMethodName = fromMethod.name
            if (!fromMethodName.contains("get")) continue
            //排除列表检测
            val str = fromMethodName.substring(3)
            if (includesList != null) {
                if (!includesList.contains(str.substring(0, 1).toLowerCase() + str.substring(1))) {
                    continue
                }
            }
            toMethodName = "set" + fromMethodName.substring(3)
            toMethod = findMethodByName(toMethods, toMethodName)
            if (toMethod == null) continue
            val value = fromMethod.invoke(from, *arrayOfNulls(0)) ?: continue
            //集合类判空处理
            if (value is Collection<*>) {
                if (value.size <= 0) continue
            }
            toMethod.invoke(to, value)
        }
    }

    /**
     * 从方法数组中获取指定名称的方法
     *
     * @param methods
     * @param name
     * @return
     */
    private fun findMethodByName(methods: Array<Method>, name: String): Method? {
        for (j in methods.indices) {
            if (methods[j].name == name) return methods[j]
        }
        return null
    }
}